<template>
  <div class="head-container">
    <div v-if="searchToggle && searchParamsArray.length > 0" id="selectDiv">
      <el-row :gutter="10" type="flex" class="flex-warp">
        <el-col
          v-for="searchParams in searchParamsArray.filter((element) => element.type === 'school')"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-select
            v-model="searchParams.value"
            filterable
            clearable
            size="medium"
            :placeholder="searchParams.placeholder"
            class="w-full"
            @change="(value) => selectChange(searchParams.method,value)"
          >
            <el-option
              v-for="(item, optionIndex) in schoolList"
              :key="optionIndex"
              :value="item.schoolId"
              :label="item.schoolName"
            />
          </el-select>
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter((element) => element.type === 'cascader')"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-cascader
            v-model="searchParams.valueArray"
            class="w-full"
            filterable
            :options="searchParams.options"
            :placeholder="searchParams.placeholder"
            :props="{
              multiple: searchParams.multiple ? searchParams.multiple : false,
              checkStrictly: searchParams.checkStrictly ? searchParams.checkStrictly : true,
              expandTrigger: searchParams.expandTrigger ? searchParams.expandTrigger : 'hover'
            }"
            clearable
            @change="(value) => selectChange(searchParams.method,value)"
          />
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter((element) => element.type === 'input')"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-input
            v-model="searchParams.value"
            size="medium"
            clearable
            :placeholder="searchParams.placeholder"
            :maxlength="searchParams.maxlength ? searchParams.maxlength : defaultMaxLength"
            class="filter-item"
            @keyup.enter.native="search"
          />
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter((element) => element.type === 'select')"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-select
            v-model="searchParams.value"
            filterable
            clearable
            size="medium"
            :placeholder="searchParams.placeholder"
            class="w-full"
            @change="(value) => selectChange(searchParams.method,value)"
          >
            <el-option
              v-for="(item, optionIndex) in searchParams.options"
              :key="optionIndex"
              :value="optionValue(item, searchParams.code)"
              :label="optionValueName(item, searchParams.text)"
            />
          </el-select>
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter(
            (element) => element.type === 'multipleSelect'
          )"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-select
            v-model="searchParams.valueArray"
            multiple
            default-first-option
            filterable
            clearable
            size="medium"
            :placeholder="searchParams.placeholder"
            class="w-full"
          >
            <el-option
              v-for="(item, optionIndex) in searchParams.options"
              :key="optionIndex"
              :value="optionValue(item, searchParams.code)"
              :label="optionValueName(item, searchParams.text)"
            />
          </el-select>
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter((element) => element.type === 'date')"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-date-picker
            v-model="searchParams.value"
            :value-format="searchParams.format"
            :format="searchParams.format"
            type="date"
            size="medium"
            :placeholder="searchParams.placeholder"
            :picker-options="searchParams.pickerOptions"
            class="w-full"
          />
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter(
            (element) => element.type === 'daterange'
          )"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-date-picker
            v-model="searchParams.valueArray"
            :value-format="searchParams.format"
            type="daterange"
            size="medium"
            range-separator="至"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            :picker-options="searchParams.pickerOptions"
            class="w-full"
          />
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter((element) => element.type === 'datetime')"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-date-picker
            v-model="searchParams.value"
            :value-format="searchParams.format"
            :format="searchParams.format"
            type="date"
            size="medium"
            :placeholder="searchParams.placeholder"
            :picker-options="searchParams.pickerOptions"
            class="w-full"
          />
        </el-col>
        <el-col
          v-for="searchParams in searchParamsArray.filter(
            (element) => element.type === 'datetimerange'
          )"
          :key="searchParams.field"
          :xs="12"
          :sm="8"
          :md="6"
          :lg="6"
          :xl="4"
        >
          <el-date-picker
            v-model="searchParams.valueArray"
            :value-format="searchParams.format"
            :format="searchParams.format"
            type="datetimerange"
            size="medium"
            range-separator="-"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            :picker-options="searchParams.pickerOptions"
            class="w-full"
          />
        </el-col>
        <el-col :xs="12" :sm="8" :md="6" :lg="6" :xl="4">
          <el-button
            class="filter-item"
            size="medium"
            type="primary"
            icon="el-icon-search"
            @click="search"
          >搜索</el-button>
          <el-button
            class="filter-item"
            size="medium"
            icon="el-icon-refresh-left"
            @click="reset"
          >重置</el-button>
        </el-col>
      </el-row>
    </div>
    <vxe-grid
      :id="uniqueId"
      ref="xTable"
      border
      resizable
      auto-resize
      column-key
      highlight-hover-row
      highlight-current-row
      highlight-hover-column
      highlight-current-column
      show-overflow
      show-header-overflow
      class="sortable-column drag-table-style"
      :loading="loading"
      :row-class-name="rowClassName"
      :checkbox-config="checkboxConfig"
      :radio-config="radioConfig"
      :sort-config="{ trigger: 'cell' }"
      remote-filter
      :max-height="maxHeight"
      :columns="tableColumn"
      :data="tableData"
      :row-id="rowId"
      :edit-config="editConfig"
      @sort-change="sortChange"
      @filter-change="filterChange"
      @cell-click="cellClick"
      @radio-change="radioChange"
      @checkbox-change="checkboxChange"
      @checkbox-all="checkboxAll"
      @edit-closed="editClosed"
    >
      <template v-if="showtools" v-slot:toolbar>
        <vxe-toolbar custom>
          <template v-slot:buttons>
            <toolbar-button :button-list="leftButton" />
          </template>
          <template v-slot:tools>
            <toolbar-button :button-list="rightButton" />
            <el-button-group>
              <el-button
                v-if="searchParamsArray.length > 0"
                size="medium"
                plain
                type="info"
                icon="el-icon-search"
                @click="clickSearchToggle"
              >显隐</el-button>
              <el-button size="medium" icon="el-icon-refresh" @click="reset">刷新</el-button>
              <el-button
                v-if="columnStorage"
                size="medium"
                icon="el-icon-s-tools"
                @click="resetUserTableCofig"
              >重置表头</el-button>
              <el-button
                v-if="columnStorage && roles.indexOf('ADMIN') !== -1"
                size="medium"
                icon="el-icon-setting"
                @click="resetAllUserTableCofig"
              >重置用户表头</el-button>
            </el-button-group>
          </template>
        </vxe-toolbar>
      </template>
    </vxe-grid>
    <el-pagination
      v-if="showPagination"
      :page-size.sync="page.pageSize"
      :total="page.count"
      :current-page.sync="page.pageNum"
      style="margin-top: 8px; float: right"
      layout="total, prev, pager, next, sizes, jumper"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
    <el-dialog
    class="small-dialog"
      :visible.sync="visible"
      append-to-body
      :close-on-click-modal="false"
      title="导出"
      @close="cancel"
    >
      <el-checkbox-group v-model="checkList">
        <el-row type="flex" justify="space-between" class="flex-warp">
          <el-col v-for="(data, index) in dataArray" :key="index" :span="6">
            <el-checkbox :label="data.key">{{ data.label }}</el-checkbox>
          </el-col>
        </el-row>
      </el-checkbox-group>
      <div slot="footer" class="dialog-footer">
        <el-button @click="visible = false">取消</el-button>
        <el-button :loading="exportLoading" type="primary" @click="confirmExport">确认</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { deleteMethod } from '@/utils/common'
import Sortable from 'sortablejs'
import { mapGetters } from 'vuex'
export default {
  name: 'PTable',
  props: {
    // 唯一ID最好和组件的唯一name一样
    uniqueId: {
      type: String,
      required: true
    },
    showtools: {
      type: Boolean,
      default: true
    },
    rowId: {
      type: String,
      default: () => {
        return 'id'
      }
    },
    // 列表查询接口
    method: {
      type: Function
    },
    // 条件查询的参数
    searchParams: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 列表展示的字段
    tableColumn: {
      type: Array,
      required: true,
      default: () => {
        return []
      }
    },
    // 行的样式rowClassName
    rowClassName: {
      type: [String, Function]
    },
    checkboxConfig: {
      type: Object,
      default: () => {
        return {}
      }
    },
    radioConfig: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // toolebar的左边的按钮
    leftButton: {
      type: Array,
      default: () => {
        return []
      }
    },
    // toolebar的右边的按钮
    rightButton: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 列表查询的默认的参数，不在查询条件里显示
    defaultSearchParams: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // 列表字段顺序是否存redis
    columnStorage: {
      type: Boolean,
      default: false
    },
    // 是否显示分页
    showPagination: {
      type: Boolean,
      default: true
    },
    dicOption: {
      type: Object,
      default: () => {
        return {}
      }
    },
    editConfig: {
      type: [Boolean, Object],
      default: () => {

      }
    }
  },
  data() {
    return {
      // 设置输入框的默认最大长度为20
      defaultMaxLength: 200,
      page: {
        pageNum: 1,
        pageSize: 10,
        count: 0
      },
      searchParamsArray: this.searchParams,
      searchToggle: true,
      loading: false,
      tableData: [],
      orderSearchParams: {
        orderByColumn: '',
        isAsc: ''
      },
      maxHeight: 0,
      fullColumn: [],
      checkList: [],
      dataArray: [],
      visible: false,
      exportLoading: false,
      exportMethod: '',
      fileName: ''
    }
  },
  computed: {
    ...mapGetters(['roles']),
    schoolList() {
      return this.$store.state.user.schoolList
    }
  },
  watch: {
    searchParams(val) {
      this.searchParamsArray = val
    }
  },
  mounted() {
    this.columnDrop()
    this.getMaxHeight()
  },
  created() {
    // 如果当前人只有一个校区，默认选中当前校区
    if (this.schoolList.length === 1 && this.searchParamsArray.length > 0) {
      for (let i = 0; i < this.searchParamsArray.length; i++) {
        let item = this.searchParamsArray[i]
        if (item.type === 'school') {
          this.searchParams[i].value = this.schoolList[0].schoolId
          break
        }
      }
    }
    this.getDictionaryList()
    if (this.columnStorage) {
      this.getUserTabConfig()
    }
    this.getTableList()
  },
  methods: {
    showLoading(loading) {
      this.loading = loading
    },
    columnDrop() {
      this.$nextTick(() => {
        let xTable = this.$refs.xTable
        this.sortable = Sortable.create(xTable.$el.querySelector('.body--wrapper>.vxe-table--header .vxe-header--row'), {
          handle: '.vxe-header--column:not(.col--fixed)',
          onEnd: ({ item, newIndex, oldIndex }) => {
            let { fullColumn, tableColumn } = xTable.getTableColumn()
            let targetThElem = item
            let wrapperElem = targetThElem.parentNode
            let newColumn = fullColumn[newIndex]
            if (newColumn.fixed) {
              // 错误的移动
              if (newIndex > oldIndex) {
                wrapperElem.insertBefore(targetThElem, wrapperElem.children[oldIndex])
              } else {
                wrapperElem.insertBefore(wrapperElem.children[oldIndex], targetThElem)
              }
              return this.$XModal.message({ message: '固定列不允许拖动！', status: 'error' })
            }
            // 转换真实索引
            let oldColumnIndex = xTable.getColumnIndex(tableColumn[oldIndex])
            let newColumnIndex = xTable.getColumnIndex(tableColumn[newIndex])
            // 移动到目标列
            let currRow = fullColumn.splice(oldColumnIndex, 1)[0]
            fullColumn.splice(newColumnIndex, 0, currRow)
            xTable.loadColumn(fullColumn)
            if (this.columnStorage) {
              this.saveUserTableConfig(fullColumn)
            }
          }
        })
      })
    },
    getMaxHeight() {
      this.$nextTick(() => {
        let allHeight = document.documentElement.clientHeight
        let navbar = document.getElementsByClassName('navbar')[0].clientHeight
        let selectDiv = 0
        if (document.getElementById('selectDiv')) {
          selectDiv = document.getElementById('selectDiv').clientHeight
        }
        this.maxHeight = (allHeight - navbar - 106 - selectDiv)
      })
    },
    search() {
      this.page.pageNum = 1
      this.getTableList()
    },
    reset() {
      this.searchParamsArray.forEach(element => {
        switch (element.type) {
          case 'multipleSelect':
          case 'daterange':
          case 'datetimerange':
          case 'cascader':
            element.value = ''
            element.valueArray = element.defaultValue ? element.defaultValue : []
            break
          case 'school':
            if (element.config && element.config === 'must') {
              if (this.searchParamsArray.length > 0) {
                element.value = this.schoolList[0].schoolId
              }
            } else {
              if (this.schoolList.length === 1 && this.searchParamsArray.length > 0) {
                element.value = this.schoolList[0].schoolId
              } else {
                element.value = ''
              }
            }
            break
          case 'schoolMust':
            if (this.searchParamsArray.length > 0) {
              element.value = this.schoolList[0].schoolId
            }
            break
          default:
            element.value = element.defaultValue ? element.defaultValue : ''
        }
      })
      this.$emit('search-reset')
      this.page.pageNum = 1
      this.orderSearchParams = {}
      this.$refs.xTable.clearAll()
      this.getTableList()
    },
    getTableList() {
      this.loading = true
      let searchParams = {}
      this.searchParamsArray.forEach(element => {
        let key = element.field
        let value = element.value
        switch (element.type) {
          case 'multipleSelect':
            searchParams[key] = element.valueArray.join(',')
            break
          case 'daterange':
          case 'datetimerange':
            if (element.valueArray.length > 0) {
              searchParams[key + 'Start'] = element.valueArray[0]
              searchParams[key + 'End'] = element.valueArray[1]
            }
            break
          case 'cascader':
            element.fieldArray.forEach((key, index) => {
              searchParams[key] = element.valueArray[index]
            })
            break
          default:
            searchParams[key] = value
        }
      })
      let params = Object.assign({}, this.page, searchParams)
      params = Object.assign({}, params, this.orderSearchParams)
      params = Object.assign({}, params, this.defaultSearchParams)
      this.method(params).then(res => {
        this.page.count = res.count
        this.tableData = res.data
        this.$emit('tableData', this.tableData)
        this.loading = false
        this.getMaxHeight()
      }).catch(() => {
        this.loading = false
      })
    },
    optionValue(item, selectCode) {
      return selectCode === undefined ? item.code : item[selectCode]
    },
    optionValueName(item, selectCodeName) {
      return selectCodeName === undefined ? item.text : item[selectCodeName]
    },
    handleSizeChange(pageSize) {
      this.page.pageSize = pageSize
      this.getTableList()
    },
    handleCurrentChange(currentPage) {
      this.page.pageNum = currentPage
      this.getTableList()
    },
    clickSearchToggle() {
      this.searchToggle = !this.searchToggle
      this.getMaxHeight()
    },
    sortChange({ column, property, order }) {
      if (order) {
        this.$set(this.orderSearchParams, 'orderByColumn', property)
        this.$set(this.orderSearchParams, 'isAsc', order)
      } else {
        this.$set(this.orderSearchParams, 'orderByColumn', '')
        this.$set(this.orderSearchParams, 'isAsc', '')
      }
      this.page.pageNum = 1
      this.getTableList()
    },
    filterChange({ column, property, values, datas, filters }) {
      filters.forEach(element => {
        let value = element.datas[0] === undefined ? '' : element.datas[0]
        this.$set(this.orderSearchParams, element.field, value)
      })
      this.page.pageNum = 1
      this.getTableList()
    },
    getDictionaryList() {
      let types = this.searchParamsArray.filter(searchParams => { return searchParams.dicKey }).map(searchParams => searchParams.dicKey)
      let dicKey = Object.keys(this.dicOption)
      types = types.concat(dicKey)
      if (types.length > 0) {
        let params = {
          types: types.join(',')
        }
        this.$api.getListByTypesDictionary(params).then(res => {
          let data = res.data
          this.searchParamsArray.forEach(element => {
            types.forEach(item => {
              if (item === element.dicKey) {
                element.options = data[item]
              } else {
                this.dicOption[item] = data[item]
              }
            })
          })
        })
      }
    },
    beforeDestroy() {
      if (this.sortable) {
        this.sortable.destroy()
      }
    },
    saveUserTableConfig(fullColumn) {
      let columnNum = []
      fullColumn.forEach((Element, index) => {
        columnNum.push({ property: Element.property })
      })
      let key = this.uniqueId
      let value = JSON.stringify(columnNum)
      let params = { key, value }
      this.$api.saveUserTableConfig(params).then((res) => { })
    },
    getUserTabConfig() {
      this.$nextTick(() => {
        let key = this.uniqueId
        let params = { key }
        let { fullColumn } = this.$refs.xTable.getTableColumn()
        this.fullColumn = fullColumn
        this.$api.getUserTabConfig(params).then(({ data }) => {
          if (data.length > 0) {
            let newColumn = JSON.parse(data)
            let fullColumnNew = []
            if (newColumn) {
              newColumn.forEach(Element => {
                fullColumn.forEach(element => {
                  if (Element.property === element.property) {
                    fullColumnNew.push(element)
                  }
                })
              })
              this.$refs.xTable.loadColumn(fullColumnNew)
            }
          }
        })
      })
    },
    resetUserTableCofig() {
      this.$confirm(`重置表头后，表头顺序将变为初始状态?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$api.deleteUserTabConfig({ key: this.uniqueId }).then(() => {
          this.$refs.xTable.reloadColumn(this.fullColumn)
        })
      })
    },
    resetAllUserTableCofig() {
      this.$confirm(`重置表头后，所有用户表头顺序将变为初始状态?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$api.deleteAllUserTabConfig({ key: this.uniqueId }).then(() => {
          this.$refs.xTable.reloadColumn(this.fullColumn)
        })
      })
    },
    cellClick({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, triggerRadio, triggerCheckbox, $event }) {
      this.$emit('cell-click', { row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, triggerRadio, triggerCheckbox, $event })
    },
    radioChange({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event }) {
      this.$emit('radio-change', { row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event })
    },
    checkboxChange({ records, reserves, indeterminates, checked, row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event }) {
      this.$emit('checkbox-change', { records, reserves, indeterminates, checked, row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event })
    },
    checkboxAll({ records, reserves, indeterminates, checked, $event }) {
      this.$emit('checkbox-all', { records, reserves, indeterminates, checked, $event })
    },
    editClosed({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex }) {
      this.$emit('edit-closed', { row, rowIndex, $rowIndex, column, columnIndex, $columnIndex })
    },
    confirmExport() {
      this.exportLoading = true
      let searchParams = {}
      this.searchParamsArray.forEach(element => {
        let key = element.field
        let value = element.value
        if (element.type === 'multipleSelect') {
          searchParams[key] = element.valueArray.join(',')
        } else if (element.type === 'daterange' || element.type === 'datetimerange') {
          let start = key + 'Start'
          let end = key + 'End'
          if (element.valueArray.length > 0) {
            searchParams[start] = element.valueArray[0]
            searchParams[end] = element.valueArray[1]
          }
        } else {
          searchParams[key] = value
        }
      })
      let param = Object.assign({}, this.page, searchParams)
      param = Object.assign({}, param, this.orderSearchParams)
      param = Object.assign({}, param, this.defaultSearchParams)
      let params = {
        condition: param
      }
      let value = this.checkDataValue(this.checkList)
      params = Object.assign(params, value)
      this.exportMethod(params).then(res => {
        this.exportLoading = false
        var url = window.URL.createObjectURL(new Blob([res], { type: 'application/vnd.ms-excel' }))
        var aLink = document.createElement('a')
        aLink.style.display = 'none'
        aLink.href = url
        console.log(this.fileName)
        aLink.setAttribute('download', this.fileName + '.xls')
        document.body.appendChild(aLink)
        aLink.click()
        document.body.removeChild(aLink)
        window.URL.revokeObjectURL(url)
        this.cancel()
      }).catch(() => {
        this.exportLoading = false
      })
    },
    export(exportMethod, fileName) {
      this.exportMethod = exportMethod
      this.fileName = fileName
      this.visible = true
      this.dataArray = []
      let tableColumn = this.$deepClone(this.tableColumn)
      tableColumn = tableColumn.filter(element => element.field !== 'operation')
      Object.keys(tableColumn).forEach(key => {
        this.dataArray.push({
          key: tableColumn[key].field,
          label: tableColumn[key].title
        })
        this.checkList.push(tableColumn[key].field)
      })
    },
    async handleImport(method, file, params) {
      this.$message({
        message: '上传中...',
        type: 'info'
      })
      let formData = new FormData()
      formData.append('file', file.file)
      await method(formData, params)
      this.$message({
        message: '上传成功',
        type: 'success'
      })
      this.getTableList()
    },
    async handleDelete(method, params) {
      await deleteMethod(this, method, params)
      this.getTableList()
    },
    cancel() {
      this.visible = false
      this.exportMethod = ''
      this.fileName = ''
      this.dataArray = []
      this.checkList = []
    },
    checkDataValue(value) {
      let params = {}
      value.forEach(Element => {
        this.dataArray.forEach(element => {
          if (Element === element.key) {
            let obj = {}
            obj[element.key] = element.label
            params = Object.assign(obj, params)
          }
        })
      })
      let jsonValue = {
        filed: params
      }
      return jsonValue
    },
    selectChange(method, value) {
      if (method) {
        method(value)
      }
    }
  }
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
@import '@/styles/table.scss';

.sortable-column-demo .vxe-header--row .vxe-header--column.sortable-ghost,
.sortable-column-demo .vxe-header--row .vxe-header--column.sortable-chosen {
  background-color: #dfecfb;
}
.sortable-column-demo .vxe-header--row .vxe-header--column.col--fixed {
  cursor: no-drop;
}
.flex-warp {
  flex-wrap: wrap;
}
</style>
